package cn.xzqwjw.taskmanager.controller.api;

import cn.xzqwjw.taskmanager.domain.pojo.UlFile;
import cn.xzqwjw.taskmanager.service.UlFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Objects;

/**
 * 文件上传下载的管理控制器
 *
 * @author rush
 */
@RestController
@RequestMapping("/api/file")
@Validated
public class UlFileController {

  private final UlFileService ulFileService;

  @Autowired
  public UlFileController(UlFileService ulFileService) {
    this.ulFileService = ulFileService;
  }

  // ==================== 上传文件操作相关 ====================

  @PostMapping("/upload")
  public String upload(
      @NotNull(message = "上传管理员id不能为空")
      @Min(value = 1, message = "管理员id必须大于0")
      @RequestParam(value = "AdminId") int idAdmin,
      @RequestParam(value = "TaskId", defaultValue = "0") int idTask,
      @RequestParam(value = "FileNameShow", defaultValue = "") String fileNameShow,
      @NotNull(message = "要上传的文件不能为空")
      @RequestBody MultipartFile file) {
    return ulFileService.upload2Local(idAdmin, idTask, fileNameShow, file);
  }

  @PostMapping("/upload-multi")
  public String uploadMulti(
      @NotNull(message = "上传管理员id不能为空")
      @Min(value = 1, message = "管理员id必须大于0")
      @RequestParam(value = "AdminId") int idAdmin,
      @RequestParam(value = "TaskId", defaultValue = "0") int idTask,
      @NotNull(message = "参数不能为空")
      @RequestBody MultipartFile[] files) {
    return ulFileService.upload2LocalMulti(idAdmin, idTask, files);
  }

  // ==================== 下载文件 ====================

  /*
   * 如果路径是“/api/file/foo.pdf.png.doc”，那么 filename 变量值是 foo.pdf.png
   * 最后一个 . 被截断了，需要使用正则表达式进行路径匹配
   * 映射为：@GetMapping("/api/file/{filename:.+}")
   * 一个 * 匹配一层目录，二个 * 匹配多层目录
   * 必须要header中 Accept 头中包含了 "text/html" 的请求
   * 必须要header中 Content-Type 为 "application/json" 类型 的请求
   * 必须要header中带 testHeader=sid 的请求才处理
   * @RequestMapping(
   *  value = "/produces",
   *  produces = {"text/html"},
   *  consumes = {"application/json"},
   *  headers = {"testHeader = sid"})
   * public String testProduces(String name)
   * { return "test requestMapping produces attribute! "+name; }
   */

  @GetMapping("/download/stream/{uuid}")
  public void downloadAsStream(
      @NotBlank(message = "文件uuid不能为空")
      @PathVariable String uuid) {
    ServletRequestAttributes requestAttributes =
        (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    if (Objects.isNull(requestAttributes)) {
      return;
    }
    HttpServletResponse response = requestAttributes.getResponse();
    if (Objects.isNull(response)) {
      return;
    }
    ulFileService.downloadAsStream(response, uuid);
  }

  /**
   * 通过 ResponseEntity 实现封装 ResponseEntity，将文件流写入body中
   * 这里注意一点，文件的格式需要根据具体文件的类型来设置，一般默认为 application/octet-stream
   * 文件头中设置缓存以及文件的名字，文件的名字写入了，就可以避免出现文件随机产生名字，而不能识别的问题
   */
  @GetMapping("/download/entity/{uuid}")
  public ResponseEntity<InputStreamResource> downloadAsResponseEntity(
      @NotBlank(message = "文件uuid不能为空")
      @PathVariable String uuid) {
    return ulFileService.downloadAsResponseEntity(uuid);
  }

  // ==================== 显示图片文件 ====================

  @GetMapping(
      value = "/image/{uuid}",
      produces = {
          MediaType.IMAGE_JPEG_VALUE,
          MediaType.IMAGE_GIF_VALUE,
          MediaType.IMAGE_PNG_VALUE
      }
  )
  public byte[] showImgAsStream(
      HttpServletResponse response,
      @RequestParam(value = "FlagThumb", defaultValue = "false") Boolean flagThumb,
      @NotBlank(message = "文件uuid不能为空")
      @PathVariable String uuid) {
    return ulFileService.showImgAsStream(response, uuid, flagThumb);
  }

  // ==================== 文件管理 ====================

  /**
   * 处理 "/api/file/{id:[0-9]+}" 的 DELETE 请求，删除一条上传的文件记录
   * 一般用于后台管理上传文件时使用
   */
  @DeleteMapping("/{id:[0-9]+}")
  public String delById(
      @NotNull(message = "id不能为空")
      @Min(value = 1, message = "id必须大于0")
      @PathVariable int id) {
    return ulFileService.delById(id);
  }

  /**
   * 处理 "/api/file?uuid=XXX" 的 DELETE 请求，删除一条上传的文件记录
   * 一般用于文件上传后马上删除
   */
  @DeleteMapping("")
  public String delByUuid(
      @NotBlank(message = "uuid 不能为空")
      @RequestParam(value = "uuid") String uuid) {
    return ulFileService.delByUuid(uuid);
  }

  /**
   * 处理 "/api/file" 的 PUT 请求，修改一条上传的文件信息
   */
  @PutMapping("")
  public String modifyAll(
      @NotNull(message = "参数不能为空")
      @Valid @RequestBody UlFile file) {
    return ulFileService.modifyAll(file);
  }

  /**
   * 处理 "/api/file/{id}" 的 PATCH 请求，修改 tag、file_name、remark
   */
  @PatchMapping("/{id:[0-9]+}")
  public String patchByParams(
      @NotNull(message = "id不能为空")
      @Min(value = 1, message = "id必须大于0")
      @PathVariable int id,
      @NotBlank(message = "参数不能为空")
      @RequestBody String paramsJson) {
    return ulFileService.patchByParams(id, paramsJson);
  }

  /**
   * 根据id查询得到某个上传文件的详情
   */
  @GetMapping("/{id:[0-9]+}")
  public String queryById(
      @NotNull(message = "id不能为空")
      @Min(value = 1, message = "id必须大于0")
      @PathVariable int id) {
    return ulFileService.queryById(id);
  }

  /**
   * 根据uuid查询得到某个上传文件的详情
   */
  @GetMapping("")
  public String queryByUuid(
      @NotBlank(message = "uuid 不能为空")
      @RequestParam(value = "uuid") String uuid) {
    return ulFileService.queryByUuid(uuid);
  }

  /**
   * 得到管理员上传到服务器上的文件分页数据
   */
  @GetMapping("/list-page")
  public String listPage(
      @RequestParam(value = "PageCurrent", defaultValue = "1") int pageCurrent,
      @RequestParam(value = "PageSize", defaultValue = "20") int pageSize) {
    return ulFileService.listPage(pageCurrent, pageSize);
  }

  /**
   * 得到管理员上传到服务器上的文件分页数据
   */
  @GetMapping("/list-all")
  public String listAll(
      @NotNull(message = "任务id不能为空")
      @Min(value = 1, message = "任务id必须大于0")
      @RequestParam(value = "TaskId") int idTask) {
    return ulFileService.listAll(idTask);
  }

}
